package org.gateway.example.filter;
import org.gateway.example.utils.SignUtils;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Component
public class SignGlobalFilter implements GlobalFilter, Ordered {

    private static final String AES_KEY = "mysecretkey12345!"; // 16字节 AES 密钥
    private static final List<String> WHITE_LIST = Arrays.asList(
            "/usp/out-api/auth/whiteApi",  // 示例白名单路径
            "/public"
    );

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();

        // 1. 白名单路径直接放行
        if (isWhiteListed(path)) {
            return chain.filter(exchange);
        }

        // 2. 装饰响应以处理 JSON 内容
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();

        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                // 3. 仅处理 JSON 响应
                if (isJsonResponse(this)) {
                    return Flux.from(body)
                            .collectList()
                            .flatMap(list -> {
                                // 4. 合并响应体内容
                                DataBuffer composite = bufferFactory.join(list);
                                byte[] content = new byte[composite.readableByteCount()];
                                composite.read(content);
                                DataBufferUtils.release(composite);
                                String responseBody = new String(content, StandardCharsets.UTF_8);

                                // 5. 生成签名逻辑
                                try {
                                    // 参数3：响应体 MD5
                                    String dataMd5 = SignUtils.md5(responseBody);
                                    List<String> param3 = SignUtils.splitString(dataMd5, 6);

                                    // 参数1：请求头中的签名
                                    String param1 = request.getHeaders().getFirst("X-Sign");
                                    if (param1 == null) {
                                        return Mono.error(new IllegalArgumentException("Missing X-Sign header"));
                                    }
                                    List<String> param1List = SignUtils.splitString(param1, 10);

                                    // 参数2：请求路径 MD5
                                    String urlMd5 = SignUtils.md5(path);
                                    List<String> param2 = SignUtils.splitString(urlMd5, 8);

                                    // 合并、排序、生成最终签名
                                    List<String> combined = new ArrayList<>();
                                    combined.addAll(param1List);
                                    combined.addAll(param2);
                                    combined.addAll(param3);
                                    combined.sort((a, b) -> b.compareTo(a)); // 降序排列

                                    String combinedMd5 = SignUtils.md5(String.join("", combined));
                                    String signature = SignUtils.aesEncrypt(combinedMd5, AES_KEY);

                                    // 6. 添加签名到响应头
                                    getHeaders().add("X-Signature", signature);
                                } catch (Exception e) {
                                    return Mono.error(e);
                                }

                                // 7. 重新写入响应体
                                return super.writeWith(Flux.just(bufferFactory.wrap(content)));
                            })
                            .onErrorResume(e -> {
                                originalResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                                return originalResponse.writeWith(
                                        Flux.just(bufferFactory.wrap(e.getMessage().getBytes()))
                                );
                            });
                } else {
                    // 非 JSON 响应直接传递
                    return super.writeWith(body);
                }
            }
        };

        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    // 判断是否为白名单路径
    private boolean isWhiteListed(String path) {
        return WHITE_LIST.stream().anyMatch(path::startsWith);
    }

    // 判断是否为 JSON 响应
    private boolean isJsonResponse(ServerHttpResponse response) {
        MediaType contentType = response.getHeaders().getContentType();
        return contentType != null && contentType.includes(MediaType.APPLICATION_JSON);
    }

    @Override
    public int getOrder() {
        return -1; // 高优先级
    }
}